﻿namespace AddColumn
{
    using System;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using Outlook = Microsoft.Office.Interop.Outlook;
    using Office = Microsoft.Office.Core;

    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            const string newUserPropertyName = @"SubjectLength";
            Outlook.Folder folder = this.GetTargetFolder();
            this.RemoveUserPropertyValuesInItems(folder, newUserPropertyName);
            this.RemoveTheColumnFromView(folder, newUserPropertyName);
            this.RemoveUserPropertyFromFolder(folder, newUserPropertyName);
            this.AddUserPropertyToFolder(folder, newUserPropertyName);
            this.AddOneColumnToView(folder, newUserPropertyName);
            this.AddUserPropertyValuesToItems(folder, newUserPropertyName);
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            const string newUserPropertyName = @"SubjectLength";

            Outlook.Folder folder = this.GetTargetFolder();
            this.RemoveUserPropertyValuesInItems(folder, newUserPropertyName);
            this.RemoveTheColumnFromView(folder, newUserPropertyName);
            this.RemoveUserPropertyFromFolder(folder, newUserPropertyName);
        }

        /// <summary>
        /// Add a user property to the folder
        /// </summary>
        /// <param name="theFolder"></param>
        private void AddUserPropertyToFolder(Outlook.Folder theFolder, string userPropertyName)
        {
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return;
            }

            // If the user property is not there, create it.
            Outlook.UserDefinedProperty nameLengthProperty = null;
            try
            {
                nameLengthProperty = theFolder.UserDefinedProperties[userPropertyName];
            }
            catch (Exception ex)
            {
                Debug.WriteLine("The UserProperty is not there." + ex.Message + ex.StackTrace);
            }
            if (nameLengthProperty == null)
            {
                try
                {
                    theFolder.UserDefinedProperties.Add(userPropertyName,
                                                     Outlook.OlUserPropertyType.olText,
                                                     Type.Missing,
                                                     Type.Missing);
                }
                catch (System.Exception exc)
                {
                    Debug.WriteLine("Error in creating User Property:" + exc.Message + exc.StackTrace);
                }
            }
        }

        /// <summary>
        /// Add a new column to current view
        /// </summary>
        /// <param name="theFolder"></param>
        private void AddOneColumnToView(Outlook.Folder theFolder, string userPropertyName)
        {
            const int newColumnIndex = 1;
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return;
            }

            // Update the current view
            // IMPORTANT: Actually modifying current view is not a encouraged behaviour
            // In production code, you'd better clone a new view and change that new one at your will
            try
            {
                Outlook.TableView currentView = theFolder.CurrentView as Outlook.TableView;
                currentView.ViewFields.Insert(userPropertyName, newColumnIndex);
                currentView.Save();
                currentView.Apply();
            }
            catch (Exception exc)
            {
                Debug.WriteLine("Fail to update view: " + exc.Message + exc.StackTrace);
            }
        }

        /// <summary>
        /// Add user property values to items in the folder
        /// </summary>
        /// <param name="theFolder"></param>
        private void AddUserPropertyValuesToItems(Outlook.Folder theFolder, string propName)
        {
            if (null == theFolder || string.IsNullOrEmpty(propName))
            {
                return;
            }

            // Create user property on all mails
            Outlook.Items items = theFolder.Items;
            string columnProp = this.GetColumnProp(theFolder, propName);
            if (null != columnProp)
            {
                foreach (Outlook.MailItem theMail in items)
                {
                    try
                    {
                        Outlook.PropertyAccessor oPA = theMail.PropertyAccessor;
                        oPA.SetProperty(columnProp, theMail.Subject.Length.ToString());
                        theMail.Save();
                        Debug.WriteLine("Mail property is set: " + theMail.Subject);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("Set mail property goes wrong." + ex.Message + ex.StackTrace);
                    }
                }
            }        
        }

        /// <summary>
        /// Get the property of new column
        /// </summary>
        /// <returns></returns>
        private string GetColumnProp(Outlook.Folder theFolder, string userPropertyName)
        {
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return null;
            }

            // Get LINQ XML elements
            XElement folderViewXElement = XElement.Parse(theFolder.CurrentView.XML);
            var props = from Columns in folderViewXElement.Elements("column")
                        where (string)Columns.Element("heading") == userPropertyName
                        select Columns.Element("prop");

            // Return the first element which should be the only one
            foreach (var prop in props)
            {
                return prop.Value;            
            }
            return null;
        }

        /// <summary>
        /// Get the target working folder. We select inbox folder here
        /// </summary>
        /// <returns></returns>
        private Outlook.Folder GetTargetFolder()
        {
            // Get the inbox folder
            Outlook.Folder inboxFolder = Application.Session.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
            if (null == inboxFolder)
            {
                Debug.WriteLine("Fail to get inbox folder.");
                return null;
            }
            else
            {
                Debug.WriteLine("Folder path: " + inboxFolder.FolderPath);
            }

            if (inboxFolder.CurrentView.ViewType != Microsoft.Office.Interop.Outlook.OlViewType.olTableView)
            {
                Debug.WriteLine("This folder is not table view.");
                return null;
            }
            return inboxFolder;
        }

        /// <summary>
        /// Remove user property values in items of the folder
        /// </summary>
        /// <param name="theFolder"></param>
        private void RemoveUserPropertyValuesInItems(Outlook.Folder theFolder, string userPropertyName)
        {
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return;
            }

            // Delete the user property on all mails
            Outlook.Items items = theFolder.Items;
            string mailNameLengthPropertyName = this.GetColumnProp(theFolder, userPropertyName);
            if (null != mailNameLengthPropertyName)
            {
                foreach (Outlook.MailItem theMail in items)
                {
                    try
                    {
                        Outlook.PropertyAccessor oPA = theMail.PropertyAccessor;
                        oPA.DeleteProperty(mailNameLengthPropertyName);
                        theMail.Save();
                        Debug.WriteLine("Mail property is deleted: " + theMail.Subject);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("Fail to delete property of mailItem." + ex.Message + ex.StackTrace);
                    }
                }
            }        
        }

        /// <summary>
        /// Remove the column from table view
        /// </summary>
        /// <param name="theFolder"></param>
        private void RemoveTheColumnFromView(Outlook.Folder theFolder, string userPropertyName)
        {
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return;
            }

            // Remove view field
            Outlook.TableView currentView = theFolder.CurrentView as Outlook.TableView;
            try
            {
                currentView.ViewFields.Remove(userPropertyName);
                currentView.Save();
                currentView.Apply();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("No such field: " + ex.Message + ex.StackTrace);
            }
        }

        /// <summary>
        /// Remove folder user property
        /// </summary>
        /// <param name="theFolder"></param>
        private void RemoveUserPropertyFromFolder(Outlook.Folder theFolder, string userPropertyName)
        {
            const int newColumnIndex = 1;
            if (null == theFolder || string.IsNullOrEmpty(userPropertyName))
            {
                return;
            }

            // Remove user property
            Outlook.UserDefinedProperty nameLengthProperty = null;
            try
            {
                nameLengthProperty = theFolder.UserDefinedProperties[userPropertyName];
            }
            catch (Exception ex)
            {
                Debug.WriteLine("The UserProperty is not there." + ex.Message + ex.StackTrace);
            }
            if (nameLengthProperty != null)
            {
                try
                {
                    theFolder.UserDefinedProperties.Remove(newColumnIndex);
                }
                catch (System.Exception exc)
                {
                    Debug.WriteLine("Error removing UserProperty:" + exc.Message + exc.StackTrace);
                }
            }            
        }  

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion
    }
}
